package com.duubee.btframe.utils;

import com.alibaba.fastjson.JSONObject;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Bt 字段工具
 */
public class BtFieldUtil {

    /**
     * 通过名字获取字段
     *
     * @param object 对象
     * @param name   字段名
     * @return 字段对象
     */
    public static Field getFieldByName(Object object, String name) {

        if (object != null && BtStringUtil.isNotEmpty(name)) {
            return getFieldByName(getAllFields(object), name);
        }
        return null;
    }

    /**
     * 通过名字获取字段
     *
     * @param clazz 对象类型
     * @param name  字段名
     * @return 字段对象
     */
    public static Field getFieldByNameAndClass(Class<?> clazz, String name) {

        if (clazz != null && BtStringUtil.isNotEmpty(name)) {
            return getFieldByName(getAllFieldsByClass(clazz), name);
        }
        return null;
    }

    /**
     * 通过名字获取字段
     *
     * @param fields 字段对象数组
     * @param name   字段名
     * @return 字段对象
     */
    public static Field getFieldByName(Field[] fields, String name) {

        if (fields != null && fields.length > 0 && BtStringUtil.isNotEmpty(name)) {
            List<Field> fieldsTemp = Arrays.stream(fields).filter(field -> field != null && field.getName().equals(name)).collect(Collectors.toList());
            if (fieldsTemp.size() > 0) {
                return fieldsTemp.get(0);
            }

        }
        return null;
    }

    /**
     * 获取类的所有属性，包括父类
     *
     * @param object 对象
     * @return 所有字段数组
     */
    public static Field[] getAllFields(Object object) {
        return getAllFieldsByClass(object.getClass());
    }

    /**
     * 通过类型获取所有属性，包括父类
     *
     * @param clazz 对象类型
     * @return 所有字段数组
     */
    public static Field[] getAllFieldsByClass(Class<?> clazz) {
        List<Field> fieldList = new ArrayList<>();
        while (clazz != null) {
            fieldList.addAll(new ArrayList<>(Arrays.asList(clazz.getDeclaredFields())));
            clazz = clazz.getSuperclass();
        }
        Field[] fields = new Field[fieldList.size()];
        fieldList.toArray(fields);
        return fields;
    }

    /**
     * 获取List泛型类型
     *
     * @param field 字段
     * @return 泛型类型
     */
    public static Class<?> getListGenericType(Field field) {
        if (field != null) {
            Type type1 = field.getGenericType();
            if (type1 instanceof ParameterizedType) {
                ParameterizedType pt = (ParameterizedType) type1;
                // 得到泛型里的class类型对象
                return (Class<?>) pt.getActualTypeArguments()[0];
            }
        }
        return null;
    }


    /**
     * 类型转换对象
     */
    public static class TypeConvert {

        public static Integer parseInteger(Object object) {
            if (object != null) {
                String number = object.toString();
                if (BtStringUtil.isNumeric(number)) {
                    return Integer.valueOf(number);
                }
            }
            return null;
        }

        public static Long parseLong(Object object) {
            if (object != null) {
                String number = object.toString();
                if (BtStringUtil.isNumeric(number)) {
                    return Long.valueOf(number);
                }
            }
            return null;
        }

        public static String parseString(Object object) {
            if (object != null) {
                return object.toString();
            }
            return null;
        }

        public static Double parseDouble(Object object) {
            if (object != null) {
                String number = object.toString();
                if (BtStringUtil.isNotEmpty(number)) {
                    return Double.valueOf(number);
                }
            }
            return null;
        }

        public static BigDecimal parseBigDecimal(Object object) {
            if (object != null) {
                String number = object.toString();
                if (BtStringUtil.isNotEmpty(number)) {
                    return new BigDecimal(number);
                }
            }
            return null;
        }

        public static Date parseDate(Object object) {
            if (object != null) {
                String str = object.toString();
                if (BtStringUtil.isNotEmpty(str)) {
                    return BtDateUtil.valueOf(str);
                }
            }
            return null;
        }

        public static Boolean parseBoolean(Object object) {
            if (object != null) {
                String str = object.toString();
                if (BtStringUtil.isNotEmpty(str)) {
                    return Boolean.valueOf(str);
                }
            }
            return null;
        }

        public static Float parseFloat(Object object) {
            if (object != null) {
                String str = object.toString();
                if (BtStringUtil.isNotEmpty(str)) {
                    return Float.valueOf(str);
                }
            }
            return null;
        }

        public static Short parseShort(Object object) {
            if (object != null) {
                String str = object.toString();
                if (BtStringUtil.isNotEmpty(str)) {
                    return Short.valueOf(str);
                }
            }
            return null;
        }

        public static Byte parseByte(Object object) {
            if (object != null) {
                String str = object.toString();
                if (BtStringUtil.isNotEmpty(str)) {
                    return Byte.valueOf(str);
                }
            }
            return null;
        }

        public static byte[] parseByteArray(Object object) {
            if (object != null) {
                String str = object.toString();
                if (BtStringUtil.isNotEmpty(str)) {
                    return str.getBytes();
                }
            }
            return null;
        }

        public static Character parseCharacter(Object object) {
            if (object != null) {
                String str = object.toString();
                if (BtStringUtil.isNotEmpty(str)) {
                    return str.charAt(0);
                }
            }
            return null;
        }

        public static char[] parseCharArray(Object object) {
            if (object != null) {
                String str = object.toString();
                if (BtStringUtil.isNotEmpty(str)) {
                    return str.toCharArray();
                }
            }
            return null;
        }

        public static <T> T parseByClass(Object object, Class<T> tClass) {

            Object result;

            if (tClass == BigDecimal.class) {
                result = parseBigDecimal(object);
            } else if (tClass == String.class) {
                result = parseString(object);
            } else if (tClass == Integer.class || tClass == int.class) {
                result = parseInteger(object);
            } else if (tClass == Long.class || tClass == long.class) {
                result = parseLong(object);
            } else if (tClass == Double.class || tClass == double.class) {
                result = parseDouble(object);
            } else if (tClass == Date.class) {
                result = parseDate(object);
            } else if (tClass == Float.class || tClass == float.class) {
                result = parseFloat(object);
            } else if (tClass == Short.class || tClass == short.class) {
                result = parseShort(object);
            } else if (tClass == Byte.class || tClass == byte.class) {
                result = parseByte(object);
            } else if (tClass == Character.class || tClass == char.class) {
                result = parseCharacter(object);
            } else if (tClass == char[].class) {
                result = parseCharArray(object);
            } else if (tClass == byte[].class) {
                result = parseByteArray(object);
            } else {
                result = object;
            }
            return (T) result;
        }
    }

    /**
     * 获取值对象
     */
    public static class Get {
        /**
         * 获取对象值(Object)
         *
         * @param object 对象
         * @param name   字段名
         * @return 值
         * @throws IllegalAccessException 非法访问异常
         */
        public static Object get(Object object, String name) throws IllegalAccessException {
            Field field = getFieldByName(object, name);
            if (field != null) {
                field.setAccessible(true);
                return field.get(object);
            }
            return null;
        }

        /**
         * 获取对象值(String)
         *
         * @param object 对象
         * @param name   字段名
         * @return 值
         * @throws IllegalAccessException 非法访问异常
         */
        public static String getString(Object object, String name) throws IllegalAccessException {
            Object value = get(object, name);
            if (value != null) {
                return String.valueOf(value);
            }
            return null;
        }

        /**
         * 获取对象值(Boolean)
         *
         * @param object 对象
         * @param name   字段名
         * @return 值
         * @throws IllegalAccessException 非法访问异常
         */
        public static Boolean getBoolean(Object object, String name) throws IllegalAccessException {
            String value = getString(object, name);
            if (BtStringUtil.isNotEmpty(value)) {
                return Boolean.valueOf(value);
            }
            return null;
        }

        /**
         * 获取对象值(Integer)
         *
         * @param object 对象
         * @param name   字段名
         * @return 值
         * @throws IllegalAccessException 非法访问异常
         */
        public static Integer getInteger(Object object, String name) throws IllegalAccessException {
            String value = getString(object, name);
            if (BtStringUtil.isNumeric(value)) {
                assert value != null;
                return Integer.valueOf(value);
            }
            return null;
        }

        /**
         * 获取对象值(Date)
         *
         * @param object 对象
         * @param name   字段名
         * @return 值
         * @throws IllegalAccessException 非法访问异常
         */
        public static Date getDate(Object object, String name) throws IllegalAccessException {
            String value = getString(object, name);
            if (BtStringUtil.isNotEmpty(value)) {
                return BtDateUtil.valueOf(value);
            }
            return null;
        }

        /**
         * 获取对象值(BigDecimal)
         *
         * @param object 对象
         * @param name   字段名
         * @return 值
         * @throws IllegalAccessException 非法访问异常
         */
        public static BigDecimal getBigDecimal(Object object, String name) throws IllegalAccessException {
            String value = getString(object, name);
            if (BtStringUtil.isNotEmpty(value)) {
                return new BigDecimal(value);
            }
            return null;
        }

        /**
         * 获取对象值(Double)
         *
         * @param object 对象
         * @param name   字段名
         * @return 值
         * @throws IllegalAccessException 非法访问异常
         */
        public static Double getDouble(Object object, String name) throws IllegalAccessException {
            String value = getString(object, name);
            if (BtStringUtil.isNotEmpty(value)) {
                return Double.valueOf(value);
            }
            return null;
        }

        /**
         * 获取泛型数据
         *
         * @param object 对象
         * @param name   字段名
         * @param tClass 指定泛型类型
         * @param <T>    t
         * @return 数据
         * @throws IllegalAccessException 非法访问异常
         */
        public static <T> T getByClass(Object object, String name, Class<T> tClass) throws IllegalAccessException {
            Object value = Get.get(object, name);
            if (value != null) {
                return TypeConvert.parseByClass(value, tClass);
            }
            return null;
        }

        /**
         * 获取对象值(Object)
         *
         * @param object 对象
         * @param field  字段
         * @return 值
         * @throws IllegalAccessException 非法访问异常
         */
        public static Object get(Object object, Field field) throws IllegalAccessException {
            if (field != null) {
                field.setAccessible(true);
                return field.get(object);
            }
            return null;
        }

        /**
         * 获取对象值(String)
         *
         * @param object 对象
         * @param field  字段名
         * @return 值
         * @throws IllegalAccessException 非法访问异常
         */
        public static String getString(Object object, Field field) throws IllegalAccessException {
            Object value = get(object, field);
            if (value != null) {
                return String.valueOf(value);
            }
            return null;
        }

        /**
         * 获取对象值(Boolean)
         *
         * @param object 对象
         * @param field  字段
         * @return 值
         * @throws IllegalAccessException 非法访问异常
         */
        public static Boolean getBoolean(Object object, Field field) throws IllegalAccessException {
            String value = getString(object, field);
            if (BtStringUtil.isNotEmpty(value)) {
                return Boolean.valueOf(value);
            }
            return null;
        }

        /**
         * 获取对象值(Integer)
         *
         * @param object 对象
         * @param field  字段
         * @return 值
         * @throws IllegalAccessException 非法访问异常
         */
        public static Integer getInteger(Object object, Field field) throws IllegalAccessException {
            String value = getString(object, field);
            if (BtStringUtil.isNumeric(value)) {
                return Integer.valueOf(value);
            }
            return null;
        }

        /**
         * 获取对象值(Date)
         *
         * @param object 对象
         * @param field  字段
         * @return 值
         * @throws IllegalAccessException 非法访问异常
         */
        public static Date getDate(Object object, Field field) throws IllegalAccessException {
            String value = getString(object, field);
            if (BtStringUtil.isNotEmpty(value)) {
                return BtDateUtil.valueOf(value);
            }
            return null;
        }

        /**
         * 获取对象值(BigDecimal)
         *
         * @param object 对象
         * @param field  字段
         * @return 值
         * @throws IllegalAccessException 非法访问异常
         */
        public static BigDecimal getBigDecimal(Object object, Field field) throws IllegalAccessException {
            String value = getString(object, field);
            if (BtStringUtil.isNotEmpty(value)) {
                return new BigDecimal(value);
            }
            return null;
        }

        /**
         * 获取对象值(Double)
         *
         * @param object 对象
         * @param field  字段
         * @return 值
         * @throws IllegalAccessException 非法访问异常
         */
        public static Double getDouble(Object object, Field field) throws IllegalAccessException {
            String value = getString(object, field);
            if (BtStringUtil.isNotEmpty(value)) {
                return Double.valueOf(value);
            }
            return null;
        }


        public static <T> T getByClass(Object object, Field field, Class<T> tClass) throws IllegalAccessException {
            Object value = Get.get(object, field);
            if (value != null) {
                return TypeConvert.parseByClass(value, tClass);
            }
            return null;
        }

    }

    /**
     * 设置对象
     */
    public static class Set {

        /**
         * 设置对象数据(Object)
         *
         * @param object 对象
         * @param name   字段名
         * @param value  值
         * @throws IllegalAccessException 非法访问异常
         */
        public static void set(Object object, String name, Object value) throws IllegalAccessException {
            Field field = getFieldByName(object, name);
            if (field != null) {
                field.setAccessible(true);
                field.set(object, value);
            }
        }

        /**
         * 设置对象数据(自动验证类型)
         *
         * @param object 对象
         * @param name   字段名
         * @param value  值
         * @throws IllegalAccessException 非法访问异常
         */
        public static void setAuto(Object object, String name, Object value) throws IllegalAccessException {
            Field field = getFieldByName(object, name);
            if (field != null) {
                setAuto(object, field, value);
            }
        }

        /**
         * 设置对象数据(自动验证类型)
         *
         * @param object 对象
         * @param field  字段名
         * @param value  值
         * @throws IllegalAccessException 非法访问异常
         */
        public static void setAuto(Object object, Field field, Object value) throws IllegalAccessException {
            if (field != null) {
                field.setAccessible(true);

                if (value == null) {
                    field.set(object, null);
                } else {
                    Type type = field.getGenericType();
                    if (type == Integer.class || type == int.class) {
                        field.setInt(object, TypeConvert.parseInteger(value));
                    } else if (type == Boolean.class || type == boolean.class) {
                        field.setBoolean(object, TypeConvert.parseBoolean(value));
                    } else if (type == Long.class || type == long.class) {
                        field.setLong(object, TypeConvert.parseLong(value));
                    } else {
                        Object temp;
                        if (type == BigDecimal.class) {
                            temp = TypeConvert.parseBigDecimal(value);
                        } else if (type == Date.class) {
                            temp = TypeConvert.parseDate(value);
                        } else {
                            temp = value;
                        }
                        field.set(object, temp);
                    }
                }
            }
        }
    }

    public static class Map {

        public static <T, M> List<M> byClass(List<T> entityList, String name, Class<M> mClass) {
            Field field;
            if (entityList == null || entityList.size() < 1 || BtStringUtil.isEmpty(name) || ((field = getFieldByName(entityList.get(0), name)) == null)) {
                return new ArrayList<>();
            }

            List<M> result = new ArrayList<>();

            entityList.forEach(item -> {
                try {
                    result.add(Get.getByClass(item, name, mClass));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            });
            return result;
        }

        public static <T> List<Integer> integers(List<T> entityList, String name) {
            return byClass(entityList, name, Integer.class);
        }

        public static <T> List<String> strings(List<T> entityList, String name) {
            return byClass(entityList, name, String.class);
        }

        public static <T> List<Boolean> booleans(List<T> entityList, String name) {
            return byClass(entityList, name, Boolean.class);
        }

        public static <T> List<BigDecimal> bigDecimals(List<T> entityList, String name) {
            return byClass(entityList, name, BigDecimal.class);
        }

        public static <T> List<Long> longs(List<T> entityList, String name) {
            return byClass(entityList, name, Long.class);
        }

        public static <T> List<Short> shorts(List<T> entityList, String name) {
            return byClass(entityList, name, Short.class);
        }

        public static <T> List<Date> dates(List<T> entityList, String name) {
            return byClass(entityList, name, Date.class);
        }
    }

}
